from starlette.endpoints import HTTPEndpoint
from starlette.responses import JSONResponse
from database import Session
from dao import DaoWorkRecord, DaoSuperviseRecord
from uuid import UUID
from model.ModPhotoIndex import PhotoIndex
import config
import logging
import tempfile
from typing import Optional, Tuple
import imagehash
from redis_connection import redis_conn as redis
from utils import Switch
from PIL import Image
import pendulum
import os
import os.path
import requests

# 运维组督办核实页面
class SuperviseConfirmOperator(HTTPEndpoint):

    async def get(self, request):
        session = Session()
        try:
            bureauid = request.query_params["bureauid"]
            flag_result = request.query_params["flag_result"]
            return DaoSuperviseRecord.get_supervise_confirm_list(session, bureauid, flag_result)
        finally:
            session.close()


# 运维组督办核实页面详细信息
class SuperviseConfirmDetail(HTTPEndpoint):
    def __init__(self, scope):
        super().__init__(scope)
        self._logger = logging.getLogger(type(self).__name__)

    async def get(self, request):
        session = Session()
        try:
            bureauid = request.query_params["bureauid"]
            meter_barcode = request.query_params["meter_barcode"]
            serial_number = request.query_params["serial_number"]
            return DaoSuperviseRecord.get_supervise_detail(session, bureauid, meter_barcode, serial_number)
        finally:
            session.close()

    async def put(self, request):
        session = Session()
        try:
            dict_rec = await request.json()
            photo_fingerprint = ""
            if len(dict_rec["photo_fingerprint_operation"]) > 0:
                photo = self._save_picture(dict_rec["photo_fingerprint_operation"])
                if photo is None:
                    raise OSError()
                photo_fingerprint, photo_path = photo
                self._logger.debug(f"Photo: {photo_fingerprint}")
                new_photo = PhotoIndex(photo_fingerprint=photo_fingerprint,
                                       storage_path=config.UPLOAD_PATH,
                                       access_path=photo_path)
                session.add(new_photo)
            serial_number = dict_rec.get("serial_number")
            bureauid = dict_rec.get("bureauid")
            meter_barcode = dict_rec.get("meter_barcode")
            flag_result = dict_rec.get("flag_result")
            openid = dict_rec.get("openid")
            time_operation = pendulum.now("Asia/Shanghai")
            name_operation = dict_rec.get("name_operation")
            remark_operation = dict_rec.get("remark_operation")

            DaoSuperviseRecord.update_result_flag(session, bureauid, UUID(serial_number), meter_barcode, flag_result, openid,
                                                  time_operation, name_operation,remark_operation,photo_fingerprint)
            session.commit()
        except Exception:
            session.rollback()
            return JSONResponse({"result": "0"})
        else:
            return JSONResponse({"result": "1"})
        finally:
            session.close()

    def _save_picture(self, media_id: str) -> Optional[Tuple[str, str]]:
        """
        用微信素材的Media ID来下载指定素材图片，并计算图片指纹。
        注意：本下载方法仅支持JPEG和PNG两种文件格式，由微信返回的响应头属性Content-Type确定。
        :param media_id: 素材Media ID
        :return: 返回元组(图片指纹，图片保存路径)，如果出现下载错误等，则返回None。
        """
        try:
            token = redis.hget(config.ENT_ACCESS_TOKEN, "token")
            media_file_request = requests.get(f"https://qyapi.weixin.qq.com/cgi-bin/media/get",
                                              params={
                                                  "access_token": token,
                                                  "media_id": media_id
                                              },
                                              stream=True)
            media_file_request.raise_for_status()

            # 判断上传的文件类型
            content_type = media_file_request.headers["Content-Type"]
            file_type = ""
            for case in Switch(content_type.lower()):
                if case("image/jpeg"):
                    file_type = "jpg"
                    break
                if case("image/png"):
                    file_type = "png"
                    break
                if case("application/json; charset=utf-8"):
                    self._logger.info(media_file_request.json())
                    raise ValueError("No image transfered")
                if case():
                    self._logger.debug(f"响应头中的Content-Type为{content_type.lower()}")
                    raise ValueError("Unsupported content type")

            # 转置到临时文件计算图片指纹，之后再转置到uploads目录
            with tempfile.TemporaryFile() as tmp:
                for chunk in media_file_request.iter_content(chunk_size=512):
                    if chunk:
                        tmp.write(chunk)
                image_fingerprint = imagehash.phash(Image.open(tmp))
                image_file_name = f"{image_fingerprint}.{file_type}"
                upload_file_name = f"{config.UPLOAD_PATH}/{image_file_name}"
                if not os.path.exists(f"{config.UPLOAD_PATH}"):
                    os.makedirs(f"{config.UPLOAD_PATH}")
                with open(upload_file_name, "wb") as upload:
                    tmp.seek(0)
                    while True:
                        content = tmp.read(512)
                        if not content:
                            break
                        upload.write(content)

            return str(image_fingerprint), image_file_name
        except OSError:
            self._logger.info("文件转置失败，将目录设为了移动目标。")
            return None
        except ValueError:
            self._logger.info("微信素材解析失败，因为Content-Type无法识别。")
            return None
        except requests.HTTPError:
            self._logger.info("微信素材下载请求失败。")
            return None

class SuperviseConfirmCount(HTTPEndpoint):
    async def get(self, request):
        session = Session()
        try:
            bureauid = request.query_params["bureauid"]
            cou = DaoSuperviseRecord.get_supervise_confirm_count(session, bureauid)
            return JSONResponse({"result": cou})
        finally:
            session.close()

